package cn.shiwei.hr.service.impl;

import cn.shiwei.hr.constants.VerifyConstants;
import cn.shiwei.hr.dto.SMSCodeDto;
import cn.shiwei.hr.repository.AssertUtil;
import cn.shiwei.hr.repository.StrUtils;
import cn.shiwei.hr.repository.VerifyCodeUtils;
import cn.shiwei.hr.service.IVerifyService;
import cn.shiwei.hr.to.SMSCodeTO;
import cn.shiwei.hr.to.SMSTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import static cn.shiwei.hr.constants.MessageConstants.EXCHANGE_NAME_TOPIC;
import static cn.shiwei.hr.constants.VerifyConstants.*;


@Service
@Slf4j
public class VerifyServiceImpl implements IVerifyService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public String getImageCode(String imageKey) {
        // 得到图形验证码的key
        // 先进行校验
        AssertUtil.stringIsEmpty(imageKey, "无效的图形验证码key");

        // 生成图形验证码, 将值存入redis, 设置三分钟有效期
        String imageCode = StrUtils.getComplexRandomString(4);
        redisTemplate.opsForValue().set(imageKey, imageCode, 3, TimeUnit.MINUTES);

        log.info("图形验证码: {}",imageCode);

        // 调用工具类生成图片, 返回前端
        String imageBase = null;
        try {
            imageBase = VerifyCodeUtils.verifyCode(imageCode);
        } catch (IOException e) {
            e.printStackTrace();
        }
        AssertUtil.stringIsEmpty(imageBase, "图形验证码生成失败");
        return imageBase;
    }

    @Override
    public void sendSmsCode(SMSCodeDto smsCodeDto) {
        // 拿到数据, 已做非空, 手机号, 校验(@Valid, @NotEmpty)
        // 先判断redis中有没有验证码(没有就是过期了)
        String cacheImageCode = (String)redisTemplate.opsForValue().get(smsCodeDto.getImageCodeKey());
        AssertUtil.stringIsEmpty(cacheImageCode, "验证码过期, 请重新获取图形验证码");

        // 判断redis中的验证码是否与用户输入一致, 忽略大小写
        AssertUtil.isTrue(cacheImageCode.equalsIgnoreCase(smsCodeDto.getImageCode()), "输入的验证码错误");

        // 通过图形验证码后, 查询redis中有无短信验证码,
        String signSMSVerify = String.format(SIGN__SMS_VERIFY, smsCodeDto.getMobile());
        SMSCodeTO smsTo = (SMSCodeTO)redisTemplate.opsForValue().get(signSMSVerify);

        // 经过验证就生成随机6位验证码,
        String smsCode = StrUtils.getComplexRandomString(6);;

        // 校验是否存在短信验证码, 如果不存在
        long nowTime = System.currentTimeMillis();
        if (smsTo != null) {
            // 如果不为空, 且当前时间-存入时间小于60, 报错
            AssertUtil.isTrue(nowTime - smsTo.getTime() > 60 * 1000, "请求过于频繁, 请稍后重试");
            // 旧的覆盖新的
            smsCode = smsTo.getSmsCode();
        }


        // 将短信验证码存入redis
        SMSCodeTO smsCodeTO = new SMSCodeTO(smsCode, smsCodeDto.getMobile());
        redisTemplate.opsForValue().set(signSMSVerify, smsCodeTO);

        // mq发送短信验证码, 此处模拟
        newsPush(smsCodeTO);

        // 清除原来的图形验证码
        redisTemplate.delete(smsCodeDto.getImageCodeKey());

        // 将验证信息存入数据库

    }

    @Value("${rabbitmq.message.sms}")
    private String SMSMessage;

    // 信息推送方法, rabbitMQ, mq 接收到消息可, 在那边调用短信接口
    private void newsPush(SMSCodeTO smsCodeTO) {
        SMSTO smsto = new SMSTO();
        smsto.setMessage(String.format(SMSMessage, smsCodeTO.getSmsCode()));
        smsto.setPhones(smsCodeTO.getPhone());
        rabbitTemplate.convertAndSend(EXCHANGE_NAME_TOPIC, "register.sms", smsto);
        log.info(smsto.toString());
    }
}
